home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 15
/
Aminet 15 - Nov 1996.iso
/
Aminet
/
dev
/
lang
/
FPL_v147.lha
/
fpl
/
src
/
sscanf.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-07-07
|
9KB
|
385 lines
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include "script.h"
#define inchar() ((c = string[pos++]), \
pos>stringlen ? \
EOF : (++read_in, c))
#define conv_error() return(done)
#define input_error() return(-1)
#define memory_error() return(-1)
#define SCALL(x) if(x) return -1;
/* Read formatted input from String according to the format string
FORMAT, using the argument list in ARG.
Return the number of assignments made, or -1 for an input error. */
long
Sscanf(struct Data *scr,
uchar *string,
uchar *format,
long argc,
void **param_array,
uchar *param_types)
{
struct Identifier *ident;
long stringlen = string?FPL_STRLEN(string):0; /* length of string to parse */
long pos=0; /* current scan point! */
char *f = format;
char fc; /* Current character of the format. */
long done = 0; /* Assignments done. */
long read_in = 0; /* Chars read in. */
long c; /* Last char read. */
long do_assign; /* Whether to do an assignment. */
long width; /* Maximum field width. */
/* Type modifiers. */
char is_short, is_long, is_long_double;
#ifdef HAVE_LONGLONG
/* We use the `L' modifier for `long long int'. */
#define is_longlong is_long_double
#else
#define is_longlong 0
#endif
/* If a [...] is a [^...]. */
char not_in;
/* Base for integral numbers. */
long base;
/* Integral holding variables. */
long num;
unsigned long unum;
/* Workspace. */
char work[200];
char *w; /* Pointer into WORK. */
long param_num = 1; /* start on (0 and 1 is the first strings) 2nd param! */
if (format == NULL) {
input_error();
}
c = inchar();
/* Run through the format string. */
while (*f != '\0') {
fc = *f++;
if (fc != '%') {
/* Characters other than format specs must just match. */
if (c == EOF)
input_error();
if (isspace(fc)) {
/* Whitespace characters match any amount of whitespace. */
while (isspace (c))
inchar ();
continue;
}
else if (c == fc)
(void) inchar();
else
conv_error();
continue;
}
/* Check for the assignment-suppressant. */
if (*f == '*') {
do_assign = 0;
++f;
}
else
do_assign = 1;
/* Find the maximum field width. */
width = 0;
while (isdigit(*f)) {
width *= 10;
width += *f++ - '0';
}
if (width == 0)
width = -1;
/* Check for type modifiers. */
is_short = is_long = is_long_double = 0;
while (*f == 'h' || *f == 'l' || *f == 'L')
switch (*f++) {
case 'h':
#if 0
/* int's are short int's. */
is_short = 1;
break;
#endif
case 'l':
#if 0
if (is_long)
/* A double `l' is equivalent to an `L'. */
is_longlong = 1;
else
/* int's are long int's. */
is_long = 1;
break;
#endif
case 'L':
#if 0
/* double's are long double's, and int's are long long int's. */
is_long_double = 1;
#endif
break;
}
/* End of the format string? */
if (*f == '\0')
conv_error();
/* Find the conversion specifier. */
w = work;
fc = *f++;
if (fc != '[' && fc != 'c' && fc != 'n')
/* Eat whitespace. */
while (isspace(c))
(void) inchar();
switch (fc) {
case '%': /* Must match a literal '%'. */
if (c != fc)
conv_error();
break;
case 'n': /* Answer number of assignments done. */
if (do_assign) {
if(++param_num>=argc)
return -1;
if(param_types[param_num] == FPL_INTVARARG) {
ident = (struct Identifier *) param_array[param_num];
ident->data.variable.var.val32[0] = read_in;
}
else
conv_error();
}
break;
case 'c': /* Match characters. */
if (do_assign) {
if(++param_num>=argc)
return -1;
if(param_types[param_num] == FPL_STRVARARG) {
ident = (struct Identifier *) param_array[param_num];
if(ident->data.variable.var.str[0])
FREE_KIND(ident->data.variable.var.str[0]);
ident->data.variable.var.str[0]=NULL;
}
else
conv_error();
}
if (c == EOF)
input_error();
if (width == -1)
width = 1;
if (do_assign) {
SCALL(AddCharBuffer(scr, &ident->data.variable.var.str[0],
ADD_RESET));
do {
SCALL(AddCharBuffer(scr, &ident->data.variable.var.str[0], c));
} while (inchar() != EOF && --width > 0);
}
else
while (inchar() != EOF && width > 0)
--width;
if (do_assign) {
SCALL(AddCharBuffer(scr, &ident->data.variable.var.str[0], ADD_FLUSH));
++done;
}
if (c == EOF)
input_error();
break;
case 's': /* Read a string. */
if (do_assign) {
if(++param_num>=argc)
return -1;
if(param_types[param_num] == FPL_STRVARARG) {
ident = (struct Identifier *) param_array[param_num];
if(ident->data.variable.var.str[0])
FREE_KIND(ident->data.variable.var.str[0]);
ident->data.variable.var.str[0]=NULL;
}
else
conv_error();
}
if (c == EOF)
input_error();
if(do_assign) {
SCALL(AddCharBuffer(scr, &ident->data.variable.var.str[0],
ADD_RESET));
}
do {
if (isspace(c))
break;
if (do_assign) {
SCALL(AddCharBuffer(scr, &ident->data.variable.var.str[0], c));
}
} while (inchar() != EOF && (width <= 0 || --width > 0));
if (do_assign) {
SCALL(AddCharBuffer(scr, &ident->data.variable.var.str[0], ADD_FLUSH));
++done;
}
break;
case 'x': /* Hexadecimal integer. */
case 'X': /* Ditto. */
base = 16;
goto number;
case 'o': /* Octal integer. */
base = 8;
goto number;
case 'u': /* Decimal integer. */
case 'd': /* Ditto. */
base = 10;
goto number;
case 'i': /* Generic number. */
base = 0;
number:;
if (c == EOF)
input_error();
/* Check for a sign. */
if (c == '-' || c == '+') {
*w++ = c;
if (width > 0)
--width;
(void) inchar();
}
/* Look for a leading indication of base. */
if (c == '0') {
if (width > 0)
--width;
*w++ = '0';
(void) inchar();
if (tolower(c) == 'x') {
if (base == 0)
base = 16;
if (base == 16) {
if (width > 0)
--width;
(void) inchar();
}
}
else if (base == 0)
base = 8;
}
if (base == 0)
base = 10;
/* Read the number into WORK. */
do {
if (base == 16 ? !isxdigit(c) :
(!isdigit(c) || c - '0' >= base))
break;
*w++ = c;
if (width > 0)
--width;
} while (inchar() != EOF && width != 0);
if (w == work ||
(w - work == 1 && (work[0] == '+' || work[0] == '-')))
/* There was on number. */
conv_error();
/* Convert the number. */
*w = '\0';
num = Strtol(work, base, &w);
if (w == work)
conv_error();
if (do_assign) {
if(++param_num>=argc)
return -1;
if(param_types[param_num] == FPL_INTVARARG) {
ident = (struct Identifier *) param_array[param_num];
ident->data.variable.var.val32[0] = num;
}
else
conv_error();
++done;
}
break;
case '[': /* Character class. */
if (do_assign) {
if(++param_num>=argc)
return -1;
if(param_types[param_num] == FPL_STRVARARG) {
ident = (struct Identifier *) param_array[param_num];
if(ident->data.variable.var.str[0])
FREE_KIND(ident->data.variable.var.str[0]);
ident->data.variable.var.str[0]=NULL;
}
else
conv_error();
}
if (c == EOF)
input_error();
if (*f == '^') {
++f;
not_in = 1;
}
else
not_in = 0;
while ((fc = *f++) != '\0' && fc != ']') {
if (fc == '-' && *f != '\0' && *f != ']' &&
w > work && w[-1] <= *f)
/* Add all characters from the one before the '-'
up to (but not including) the next format char. */
for (fc = w[-1] + 1; fc < *f; ++fc)
*w++ = fc;
else
/* Add the character to the list. */
*w++ = fc;
}
if (fc == '\0')
conv_error();
*w = '\0';
unum = read_in;
if(do_assign) {
SCALL(AddCharBuffer(scr, &ident->data.variable.var.str[0],
ADD_RESET));
}
do {
if ((strchr(work, c) == NULL) != not_in)
break;
if (do_assign) {
SCALL(AddCharBuffer(scr, &ident->data.variable.var.str[0], c));
}
if (width > 0)
--width;
} while (inchar() != EOF && width != 0);
if (read_in == unum)
conv_error();
if (do_assign) {
SCALL(AddCharBuffer(scr, &ident->data.variable.var.str[0], ADD_FLUSH));
++done;
}
break;
case 'p': /* Generic pointer. */
base = 16;
/* A PTR must be the same size as a `long int'. */
is_long = 1;
goto number;
}
}
conv_error();
}